#include<stdio.h>
#include<ctype.h>
#include<string.h> 
#include<stdlib.h>
#include "html_link.h"

#define DEBUG 1

/*
 * html tokens storing in the static array
 */
char * tags[]={
	"html","head","title","body","p","br","hr","center","pre","div","nobr","war","strong",
	"b","em","l","tt","u","h1","h2","h3","h4","h5","h6","font","basefont","big","small",
	"strike","code","kbd","samp","var","cite","blockquote","dfn","address","sub","sup","ol",
	"ul","li","menu","dir","dl","dt","dd","table","caption","tr","td","th","form","textarea",
	"input","select","option","img","a","base","frameset","frame","iframe","noframes","map",
	"area","bgsound","embed","marquee","blink","isindex","meta","link","style","span","script",
	"label","col","param"
};

/*
 * the tags which have only one tag ,no end_tag
 */
char *tags_no_end[] = {
	"area","base","basefont","br","col","frame","hr","img","input",
	"isindex","link","meta","param"
};




/*
 * deal with the attributes of a tag, and return a new pointer pointe to new cursor of html file
 */
char *process_attr(char *ptr,struct Html_node **node)
{
	char attr[1024] = {0};
	int count_1=0;
	int count_2=0;
	char value[2048] = {0};

	while(1)
	{
		count_1 = 0;
		count_2 = 0;
		int flag = 0;// 1 resprent has double quote
		
		while(isspace(*ptr) )ptr++;
		if(*ptr == '>')
			return ++ptr;
		if(*ptr == '/')
			return ptr+2;

		while(*ptr != '=' && (!isspace(*ptr)))// get the name
			attr[count_1++]=*ptr++;
		ptr++;

		attr[count_1]=0;
		while(isspace(*ptr) || (*ptr == 34))
			ptr++;

		if(*(ptr-1) == 34)
		{
			flag = 1;
		}

		if(flag)
		{
			while((*ptr != 34))
				value[count_2++] = *ptr++;
			ptr++;
		}
		else{
			while(!isspace(*ptr) && (*ptr != '>'))
				value[count_2++] = *ptr++;
		}

		value[count_2]=0;

		struct Attr_node *new_node =(struct Attr_node *)malloc(sizeof(struct Attr_node));
		new_node->name = (char *) malloc(count_1+1);
		strcpy(new_node->name,attr);
		new_node->value = (char *)malloc(count_2+1);
		strcpy(new_node->value,value);
		new_node->next = (*node)->attr; 
		(*node)->attr = new_node;
		
	}
	return NULL;
}





/*
 * the function of dealing withd text in html file
 *
 */

char *process_text(char *s,struct Html_node **html_node)
{

	char *ptr = s;
	while(*ptr != '<')
		ptr++;
	int len = ptr - s ;
	(*html_node)->text_ptr = (char *)malloc(sizeof(char)*len+1);
	strncpy((*html_node)->text_ptr,s,len);
	(*html_node)->text_ptr[len] = 0;


	(*html_node)->node_type = text;
	(*html_node)->attr = NULL;
	(*html_node)->next = NULL;

	return ptr;
}





/*
 * the function of dealing with start tags in html file
 */
char *process_start_tag(char *s,struct Html_node **html_node)
{
	char *ptr = s;
	char name[1024]={
		0
	};
	int count = 0;
	while((*ptr != ' ') && (*ptr != '>'))
		name[count++]= *ptr++;
	name[count]=0;

	int name_index;
	if((name_index = valid_token(name) )== -1)/* change to text */
	{
		while(*ptr != '>')
			ptr++;
		return ptr+1;
	}
	(*html_node)->node_type = start_tag;
	(*html_node)->attr = NULL;
	(*html_node)->text_ptr = NULL;

	(*html_node)->name_index = name_index;
	(*html_node)->next = NULL;

	return ptr;
}





/*
 * the function of dealing with end tags in html file
 */
char *process_end_tag(char *s,struct Html_node **html_node)
{
	char *ptr = s;
	while(isspace(*ptr)|| (*ptr == '<') || (*ptr == '/') || (*ptr == '\n'))
		ptr++;
	char name[1024] = {
		0
	};
	int count = 0;
	while((*ptr != ' ' ) && (*ptr != '>'))
		name[count++]=*ptr++;
	name[count]=0;
	int name_index = 0;
	if((name_index = valid_token(name)) == -1)
	{
		return process_text(s,html_node);
	}
	(*html_node)->name_index = name_index;
	(*html_node)->node_type = end_tag;
	(*html_node)->attr = NULL;
	(*html_node)->text_ptr = NULL;
	(*html_node)->next = NULL;

	while((*ptr == ' ') || *ptr == '>')
		ptr++;

	return ptr;
}





/*
 * the funciton of dealing with comments in thml file
 */
char *process_comment(char *ptr)
{
	while(1)	
	{
		if(*ptr == '>')
			return ptr+1;
		ptr++;
	}
}




/*
 *check a token whether a valid token 
 */
int valid_token(char *s)
{
	int i;
	int len = sizeof(tags)/sizeof(char *);
	for(i = 0;i<len;i++)
		if(strcmp(s,tags[i]) == 0)
			return i;
	return -1;
}

int single_tag(char *s)
{
	int len = sizeof(tags_no_end)/sizeof(char *);
	int i=0;
	while(i<len)
	{
		if(strcmp(s,tags_no_end[i])==0)
			return 1;
		i++;
	}
	return 0;
}



/*
 * change a string to lower string
 */
static int tolower_str(char *s)
{
	char *ptr = s;
	while(*ptr != 0)
	{
		if(isupper(*ptr))
			*ptr = tolower(*ptr);
		ptr++;
	}
}





/*
 * the function of generating a linked list with html node
 */
void genera_link_list(struct Html_node **root,char *s)
{
	struct Html_node **cur_node = root;
	char *ptr = s;
	while(*ptr != '\0')
	{
		while(isspace(*ptr))ptr++;

		if(*ptr == '<')
		{
			char *new_ptr;
			switch(*(ptr+1))
			{
				case '!':
					ptr = process_comment(ptr);
					while(isspace(*ptr) || (*ptr == '\n'))ptr++;
					break;
				case '/':
					*cur_node = (struct Html_node *)malloc(sizeof(struct Html_node));
					ptr =	process_end_tag(ptr+1,cur_node);
					while(isspace(*ptr) || (*ptr == '\n'))ptr++;
					cur_node = &(*cur_node)->next;
					break;
				default:
					*cur_node = (struct Html_node *)malloc(sizeof(struct Html_node));
					ptr = process_start_tag(ptr+1,cur_node);
					ptr = process_attr(ptr ,cur_node);
					while(isspace(*ptr) || (*ptr == '\n'))ptr++;
					if((*cur_node)->node_type == start_tag)
					{
						if((*cur_node)->node_type == start_tag && single_tag(tags[(*cur_node)->name_index]))
						{
							int index = (*cur_node)->name_index;
							cur_node = &(*cur_node)->next;
							*cur_node = (struct Html_node *)malloc(sizeof(struct Html_node));
							(*cur_node)->node_type = end_tag;
							(*cur_node)->text_ptr = NULL;
							(*cur_node)->name_index =index; 
							(*cur_node)->attr = NULL;
							(*cur_node)->next = NULL;
						}

					}
					cur_node = &(*cur_node)->next;
					break;
			}
		}
		else {
			*cur_node = (struct Html_node *)malloc(sizeof(struct Html_node));
			ptr = process_text(ptr ,cur_node);
			while(isspace(*ptr) || (*ptr == '\n'))ptr++;
			cur_node = &(*cur_node)->next;
		}
		while(isspace(*ptr) || (*ptr == '\n'))
			ptr++;
	}
}








/*
 * print the html_node int linked list
 * 
 */
void html_linkedlist_tostring(struct Html_node *root)
{

	struct Html_node *cur_node = root;

	while(cur_node != NULL)
	{
		if(cur_node->node_type == start_tag)
		{
			printf("<%s",tags[cur_node->name_index])	;
			struct Attr_node *att_node = cur_node->attr;
			while(att_node != NULL)
			{
				printf(" %s=%s",att_node->name,att_node->value);
				att_node = att_node->next;
			}
			printf(">\n");
		}
		else if(cur_node->node_type == end_tag)
		{
			printf("</%s>\n",tags[cur_node->name_index]);
		}
		else {
			printf("%s\n",cur_node->text_ptr);
		}
		cur_node=cur_node->next;
	}

}

/*
 * free memory of the Html_node linkedlist 
 */

static free_attr(struct Attr_node * attr)
{
	struct Attr_node *ptr =attr;
	while(attr != NULL)
	{
		ptr = attr;
		attr = attr->next;
		if(ptr->name)
		{
			free(ptr->name);
			ptr->name = NULL;
		}
		if(ptr->value)
		{
			free(ptr->value);
			ptr->value = NULL;
		}
		free(ptr);
		ptr = NULL;
	}
}
void destroy(struct Html_node *root)
{
	struct Html_node *ptr = root;		
	while(root != NULL)
	{
		ptr = root;
		root = root->next;
		if(ptr->node_type == start_tag)
		{
			free_attr(ptr->attr);
		}
		if(ptr->node_type == text)
		{
			free(ptr->text_ptr);
			ptr->text_ptr = NULL;
		}
		free(ptr);
		ptr = NULL;
	}
}
